package com.party.core.service.menu.impl;


import com.google.common.base.Function;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.party.common.paging.Page;
import com.party.common.utils.LangUtils;
import com.party.core.dao.read.menu.MenuReadDao;
import com.party.core.dao.write.menu.MenuWriteDao;
import com.party.core.model.BaseModel;
import com.party.core.model.menu.Menu;
import com.party.core.model.role.RoleMenu;
import com.party.core.model.system.SysPrivilege;
import com.party.core.model.system.SysRole;
import com.party.core.redisDao.menu.MenuRedisDao;
import com.party.core.service.menu.IMenuService;
import com.party.core.service.role.IRoleMenuService;
import com.party.core.service.system.ISysPrivilegeService;
import com.party.core.service.system.ISysRoleService;
import com.sun.istack.NotNull;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.map.HashedMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;


/**
 * 菜单服务实现
 * party
 * Created by wei.li
 * on 2016/8/27 0027.
 */

@Service
public class MenuService implements IMenuService {

    @Autowired
    private MenuReadDao menuReadDao;

    @Autowired
    private MenuWriteDao menuWriteDao;

    @Autowired
    private IRoleMenuService roleMenuService;

    @Autowired
    private MenuRedisDao menuRedisDao;

    @Autowired
    private ISysPrivilegeService privilegeService;

    @Autowired
    private ISysRoleService sysRoleService;

    private static final String REDIS_LIST_KEY = "menuListKey";
    private static final String REDIS_ADMIN_LIST_KEY = "adminMenuListKey";
    private static final String REDIS_WEB_LIST_KEY = "webMenuListKey";

    /**
     * 查找所有admin菜单
     *
     * @return 菜单列表
     */
    public List<Menu> listAdmin() {
        //缓存是否存在
        List<Menu> menuRedisList = menuRedisDao.popValue(REDIS_ADMIN_LIST_KEY);
        if (!CollectionUtils.isEmpty(menuRedisList)){
            return menuRedisList;
        }
        Menu search = new Menu();
        search.setParentIds("3");
        LinkedList<Menu> menuList = new LinkedList<>(menuReadDao.listPage(search, null));
        menuRedisDao.pushValue(REDIS_ADMIN_LIST_KEY, menuList);
        return menuList;
    }
    /**
     * 查找所有web菜单
     *
     * @return 菜单列表
     */
    public List<Menu> listWeb() {
        //缓存是否存在
        List<Menu> menuRedisList = menuRedisDao.popValue(REDIS_WEB_LIST_KEY);
        if (!CollectionUtils.isEmpty(menuRedisList)){
            return menuRedisList;
        }
        Menu search = new Menu();
        search.setParentIds("2");
        List<Menu> menuList = menuReadDao.listPage(search, null);
        menuRedisDao.pushValue(REDIS_WEB_LIST_KEY, menuList);
        return menuList;
    }
    /**
     * 菜单插入
     *
     * @param menu 菜单信息
     * @return 插入结果（true/false）
     */
    public String insert(Menu menu) {
        BaseModel.preInsert(menu);

        concatParentIds(menu);
        //删除缓存
        menuRedisDao.delete(REDIS_LIST_KEY);
        menuRedisDao.delete(REDIS_ADMIN_LIST_KEY);
        menuRedisDao.delete(REDIS_WEB_LIST_KEY);
        boolean result = menuWriteDao.insert(menu);
        if (result) {
            return menu.getId();
        }
        return null;
    }


    /**
     * 菜单更新
     *
     * @param menu 菜单信息
     * @return 更新结果（true/false）
     */
    public boolean update(Menu menu) {
        menu.setUpdateDate(new Date());
        //删除缓存
        menuRedisDao.delete(REDIS_LIST_KEY);
        menuRedisDao.delete(REDIS_ADMIN_LIST_KEY);
        menuRedisDao.delete(REDIS_WEB_LIST_KEY);
        Menu parent = concatParentIds(menu);
        Menu dbMenu = get(menu.getId());
        // 若修改了父节点 对应修改所有子节点的parentids
        if(!dbMenu.getParentIds().equals(menu.getParentIds())){
            // 获取所有子菜单修改parentids
            List<Menu> allChilds = getAllChilds(menu);
            for(Menu child:allChilds){
                String parentIds = child.getParentIds().replace(dbMenu.getParentIds(), menu.getParentIds());
                child.setParentIds(parentIds);
                menuWriteDao.update(child);
            }
            // 修改对应的权限的parentids
            SysPrivilege privilege = privilegeService.get(menu.getPrivilegeId());
            privilege.setParentId(parent.getPrivilegeId());
            privilegeService.update(privilege);
        }
        return menuWriteDao.update(menu);
    }

    public List<Menu> getAllChilds(Menu menu){
        if(!Strings.isNullOrEmpty(menu.getId())){
            Menu search = new Menu();
            search.setParentIds(menu.getId());
            return listPage(search, null);
        }
        return null;
    }

    private Menu concatParentIds(Menu menu) {
        if (null != menu.getParentId()) {
            Menu parent = menuReadDao.get(menu.getParentId());
            String parentIds = menu.getParentId();
            if (null != parent && null != parent.getParentId()) {
                parentIds = parent.getParentIds() + parentIds+ "," ;
            }else{
                if(!Strings.isNullOrEmpty(parentIds)){
                    parentIds+=",";
                }
            }
            menu.setParentIds(parentIds);
            return parent;
        }
        return null;
    }

    /**
     * 菜单逻辑删除
     *
     * @param id 实体主键
     * @return 删除结果（true/false）
     */
    public boolean deleteLogic(@NotNull String id) {
        if (Strings.isNullOrEmpty(id)) {
            return false;
        }
        return menuWriteDao.deleteLogic(id);
    }

    /**
     * 菜单物理删除
     *
     * @param id 实体主键
     * @return 删除结果（true/false）
     */
    @Transactional
    public boolean delete(@NotNull String id) {
        if (Strings.isNullOrEmpty(id)) {
            return false;
        }
        //删除缓存
        menuRedisDao.delete(REDIS_LIST_KEY);
        menuRedisDao.delete(REDIS_ADMIN_LIST_KEY);
        menuRedisDao.delete(REDIS_WEB_LIST_KEY);
        Menu menu = get(id);
        //删除子节点
        List<Menu> menus = getAllChilds(menu);
        for(Menu child:menus){
            menuWriteDao.delete(child.getId());
        }
        //删除权限
        privilegeService.delete(menu.getPrivilegeId());
        return menuWriteDao.delete(id);
    }

    /**
     * 菜单批量逻辑删除
     *
     * @param ids 主键集合
     * @return 删除结果（true/false）
     */
    public boolean batchDeleteLogic(@NotNull Set<String> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            return false;
        }
        return menuWriteDao.batchDeleteLogic(ids);
    }

    /**
     * 菜单批量物理删除
     *
     * @param ids 主键集合
     * @return 删除结果（true/false）
     */
    public boolean batchDelete(@NotNull Set<String> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            return false;
        }
        return menuWriteDao.batchDelete(ids);
    }

    /**
     * 根据主键获取菜单信息
     *
     * @param id 主键
     * @return 菜单信息
     */
    public Menu get(String id) {
        return menuReadDao.get(id);
    }

    /**
     * 菜单分页查询
     *
     * @param menu 菜单信息
     * @param page 分页信息
     * @return 菜单列表
     */
    public List<Menu> listPage(Menu menu, Page page) {
        return menuReadDao.listPage(menu, page);
    }

    /**
     * 查询所有菜单信息
     *
     * @param menu 菜单信息
     * @return 菜单列表
     */
    public List<Menu> list(Menu menu) {
        return menuReadDao.listPage(menu, null);
    }

    /**
     * 查找所有菜单
     *
     * @return 菜单列表
     */
    public List<Menu> listAll() {

        //缓存是否存在
/*        List<Menu> menuRedisList = menuRedisDao.popValue(REDIS_LIST_KEY);
        if (!CollectionUtils.isEmpty(menuRedisList)){
            return menuRedisList;
        }*/

        List<Menu> menuList = menuReadDao.listPage(null, null);
        menuRedisDao.pushValue(REDIS_LIST_KEY,menuList);
        return menuList;
    }

    /**
     * 根据角色查找菜单
     *
     * @param roleId 角色主键
     * @return 菜单列表
     */
    @Override
    public List<Menu> findByRoleId(String roleId) {
        List<RoleMenu> roleMenuList = roleMenuService.findByRoleId(roleId);
        return findByRoleMenu(roleMenuList);
    }

    /**
     * 根据角色查询菜单
     *
     * @param roleIds 角色集合
     * @return 菜单列表
     */
    @Override
    public List<Menu> findByRoleIds(Set<String> roleIds) {
        if (CollectionUtils.isEmpty(roleIds)) {
            return Collections.EMPTY_LIST;
        }
        List<RoleMenu> roleMenuList = roleMenuService.findByRoleIds(roleIds);
        return findByRoleMenu(roleMenuList);
    }

    /**
     * 根据角色菜单关系查询菜单
     *
     * @param roleMenuList 角色菜单列表
     * @return 菜单列表
     */
    public List<Menu> findByRoleMenu(List<RoleMenu> roleMenuList) {
        List<String> menuIdList = LangUtils.transform(roleMenuList, input -> input.getMenuId());
        List<Menu> menuList = menuReadDao.batchList(new HashSet<>(menuIdList), null, null);
        return menuList;
    }

    /**
     * 菜单批量查询
     *
     * @param ids  主键集合
     * @param menu 菜单信息
     * @param page 分页信息
     * @return 菜单列表
     */
    public List<Menu> batchList(@NotNull Set<String> ids, Menu menu, Page page) {
        if (CollectionUtils.isEmpty(ids)) {
            return Collections.EMPTY_LIST;
        }
        return menuReadDao.batchList(ids, new HashedMap(), page);
    }


    @Override
    public List<Menu> findByPermission(List<String> permissions) {
        if (CollectionUtils.isEmpty(permissions)) {
            return Collections.EMPTY_LIST;
        }
        return menuReadDao.findByPermission(permissions);
    }


    @Override
    public List<Map<String, Object>> buildTreeData(String id, List<Menu> menus, List<String> permissions, boolean isChild) {
        List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
        for (int i = menus.size(); i > 0; i--) {
            Menu menu = menus.get(i - 1);
            if (isChild) {
                if ("公众号管理".equals(menu.getName()) || "服务订购".equals(menu.getName()) || "微信模板消息".equals(menu.getName())) {
                    continue;
                }
            }
            if (null != menu.getParentId() && menu.getParentId().equals(id)) {
                if (!Strings.isNullOrEmpty(menu.getPermission()) && this.isPermitted(permissions, menu.getPermission())) {
                    HashMap<String, Object> menuMap = Maps.newHashMap();
                    menuMap.put("id", menu.getId());
                    menuMap.put("rule", menu.getRule());
                    menuMap.put("icon", menu.getIcon());
                    menuMap.put("name", menu.getName());
                    menuMap.put("href", menu.getHref());
                    menuMap.put("permission", menu.getPermission());
                    menuMap.put("children", buildTreeData(menu.getId(), menus, permissions, isChild));
                    list.add(menuMap);
                }
            }
        }
        return list;
    }

    /**
     * 检查有没有权限
     * @param permissions 权限集合
     * @param myPermission 我的权限
     * @return
     */
    protected boolean isPermitted(List<String> permissions, String myPermission) {
        for (String permission : permissions) {
            if (permission.equals(myPermission)) {
                return true;
            }
        }
        return false;
    }

    /**
     * build用户角色与权限
     *
     * @param memberId  用户
     * @param roleNames 角色集合
     * @return 权限集合
     */
    @Override
    public List<String> buildPermission(String memberId, List<String> roleNames) {
        if (roleNames == null) {
            roleNames = Lists.newArrayList();
        }
        List<SysRole> sysRoles = sysRoleService.findByMemberId(memberId);
        for (SysRole sysRole : sysRoles) {
            roleNames.add(sysRole.getCode());
        }

        // 用户权限
        List<SysPrivilege> sysPrivileges = new ArrayList<SysPrivilege>();
        for (SysRole sysRole : sysRoles) {
            sysPrivileges.addAll(privilegeService.findByRoleId(sysRole.getId()));
        }

        List<String> permissions = LangUtils.transform(sysPrivileges, new Function<SysPrivilege, String>() {
            @Override
            public String apply(SysPrivilege input) {
                return input.getPermission();
            }
        });
        return permissions;
    }
}
